#include "Lecteur.h"

#include <iostream>
using namespace std;

////////////////////////////////////////////////////////////////////////////////

Lecteur::Lecteur(LecteurSymbole * ls) : ts() {
    this->setLs(ls);
}

Lecteur::Lecteur() : ts() {
    this->setLs(NULL);
}

////////////////////////////////////////////////////////////////////////////////

Noeud* Lecteur::expression() {
    // <expression> ::= <terme> { <opAdd> <terme> }
    Noeud* term = terme();
    while (getLs()->getSymCour() == "+" || getLs()->getSymCour() == "-") {
        Symbole operateur = opAdd(); // on stocke le symbole de l'opérateur
        Noeud* termeDroit = terme(); // lecture de l'operande droit
        term = new NoeudOperateurBinaire(operateur, term, termeDroit); // const. du noeud
    }
    return term;
}

////////////////////////////////////////////////////////////////////////////////

Noeud* Lecteur::terme() {
    // <terme> ::= <facteur> { <opMult> <facteur> }

    Noeud* fact = facteur();
    while (getLs()->getSymCour() == "*" || getLs()->getSymCour() == "/") {
        Symbole operateur = opMult(); // on stocke le symbole de l'opérateur
        Noeud* factDroit = facteur(); // lecture de l'operande droit
        fact = new NoeudOperateurBinaire(operateur, fact, factDroit); // const. du noeud
    }
    return fact;
}

////////////////////////////////////////////////////////////////////////////////

Symbole Lecteur::opAdd()
// <opAdd>  ::= + | -
{
    Symbole operateur;
    if (getLs()->getSymCour() == "+" || getLs()->getSymCour() == "-") {
        operateur = getLs()->getSymCour();
        getLs()->suivant();
    } else
        erreur("<opAdd>");
    return operateur;
}

////////////////////////////////////////////////////////////////////////////////

Symbole Lecteur::opMult()
// <opAdd>  ::= + | -
{
    Symbole operateur;
    if (getLs()->getSymCour() == "*" || getLs()->getSymCour() == "/") {
        operateur = getLs()->getSymCour();
        getLs()->suivant();
    } else
        erreur("<opMult>");
    return operateur;
}

////////////////////////////////////////////////////////////////////////////////

Noeud* Lecteur::expBool()
// <expBool> ::= <termeBool> { ou <termeBool> }
{
    Noeud* terme = termeBool();
    while (getLs()->getSymCour() == "ou") {
        getLs()->suivant();
        Noeud* termeDroit = termeBool();
        terme = new NoeudOperateurBinaire(Symbole("ou"), terme, termeDroit);
    }
    return terme;
}

////////////////////////////////////////////////////////////////////////////////

Noeud* Lecteur::termeBool()
// <termeBool> ::= <relation> { et <relation> }
{
    Noeud* rel = relation();
    while (getLs()->getSymCour() == "et") {
        getLs()->suivant();
        Noeud* relationDroite = relation();
        rel = new NoeudOperateurBinaire(Symbole("et"), rel, relationDroite);
    }
    return rel;
}

////////////////////////////////////////////////////////////////////////////////

Noeud* Lecteur::relation()
//  <relation> ::= <expression> { <opRel> <expression> }
{
    Noeud* exp = expression();
    while (getLs()->getSymCour() == "==" || getLs()->getSymCour() == "!=" || getLs()->getSymCour() == "<" || getLs()->getSymCour() == ">" || getLs()->getSymCour() == "<=" || getLs()->getSymCour() == ">=") {
        Symbole operateur = opRel();
        Noeud* expressionDroite = expression();
        exp = new NoeudOperateurBinaire(operateur, exp, expressionDroite);
    }
    return exp;
}

////////////////////////////////////////////////////////////////////////////////

Symbole Lecteur::opRel()
//  <opRel> ::= == | != | < | <= | > | >=
{
    Symbole operateur;
    if (getLs()->getSymCour() == "==" || getLs()->getSymCour() == "!=" || getLs()->getSymCour() == "<" || getLs()->getSymCour() == ">" || getLs()->getSymCour() == "<=" || getLs()->getSymCour() == ">=") {
        operateur = getLs()->getSymCour();
        getLs()->suivant();
    } else {
        erreur("<opRel>");
    }
    return operateur;
}

////////////////////////////////////////////////////////////////////////////////

Symbole Lecteur::opUnaire()
//  <opUnaire> ::= - | non
{
    Symbole operateur;
    if (getLs()->getSymCour() == "-" || getLs()->getSymCour() == "non") {
        operateur = getLs()->getSymCour();
        getLs()->suivant();
    } else
        erreur("<opUnaire>");
    return operateur;
}

////////////////////////////////////////////////////////////////////////////////

void Lecteur::testerSymCour(string ch) {
    if (getLs()->getSymCour() != ch) {
        erreur(ch);
    }
}

////////////////////////////////////////////////////////////////////////////////

void Lecteur::sauterSymCour(string ch) {
    testerSymCour(ch);
    getLs()->suivant();
}

////////////////////////////////////////////////////////////////////////////////

void Lecteur::erreur(string mess) {
    cout << endl << "-------- Erreur ligne " << getLs()->getLigne() << " - Colonne "
            << getLs()->getColonne() << endl << "   Attendu : " << mess << endl
            << "   Trouve  : " << getLs()->getSymCour() << endl << endl;
    exit(0); // plus tard, on levera une exception
}
